﻿#pragma once
/**
 * @desc 数学计算库，存放所有的数学计算函数
 */
#include "AsCvDefine.h"

namespace AsCv {

	/**
	 * @desc 求点到直线的距离
	 */
	AS_ALGORITHM_EXPORT double distanceTo(const cv::Point2d& point, const Line& line);

	/**
	 * @desc 点到点的距离
	 */
	AS_ALGORITHM_EXPORT double distanceTo(const cv::Point2d& ptStart, const cv::Point2d& ptEnd);

	/**
	 * @desc 线到线的角度
	 */
	AS_ALGORITHM_EXPORT double angleTo(const Line& from, const Line& to);

	/**
	 * @desc 两条线的夹角(夹角公式)
	 */
	AS_ALGORITHM_EXPORT double crossAngle(const Line& line1, const Line& line2);

	/**
	 * @desc 两条线的夹角
	 */
	AS_ALGORITHM_EXPORT double crossAngle2(const Line& line1, const Line& line2);

	/**
	 * @desc 求两个平面的夹角
	 */
	AS_ALGORITHM_EXPORT double crossAngle(const Face& face1, const Face& face2);

	/**
	 * @desc 求两线交点
	 */
	AS_ALGORITHM_EXPORT int crossPoint(const Line& line1, const Line& line2, cv::Point2d& pt);

	/**
	 * @desc 求线在x=x0处的点
	 */
	AS_ALGORITHM_EXPORT int linePointAtX(const Line& line, double x0, cv::Point2d& pt);

	/**
	 * @desc 求线在y=y0处的点
	 */
	AS_ALGORITHM_EXPORT int linePointAtY(const Line& line, double y0, cv::Point2d& pt);

	/**
	 * @desc 弧度转角度
	 */
	AS_ALGORITHM_EXPORT double radianToDegree(double fRadian);

	/**
	 * @desc 角度转弧度
	 */
	AS_ALGORITHM_EXPORT double degreeToRadian(double degree);

	/**
	 * @desc 再次计算角度
	 */
	AS_ALGORITHM_EXPORT int againConerAngle(const std::vector<cv::Point2i>& vPoint, Line& line, double& angle);
	AS_ALGORITHM_EXPORT int againConerAngle2(const std::vector<cv::Point2i>& vPoint1, const std::vector<cv::Point2i>&vPoint2, double& angle);

	/**
	 * @desc:计算点集的算术平均值
	 * @author:王杰 2023/1/30
	 * @modify:王杰 2023/1/31
	 * @params:
	 *	edgePoints-输入点集；
	 * @ret void
	 */
	AS_ALGORITHM_EXPORT cv::Point avg(const std::vector<cv::Point>& edgePoints);
	
	/**
	 * @desc:计算刻度值
	 * @author:王杰 2023/1/30
	 * @params:
	 *	v-输入数据集；
	 *	cursorRate-刻度比率；
	 *	pSmall-低刻度值；
	 *	pBig-高刻度值
	 * @ret int。0-成功 1-失败
	 */
	template<typename _TYPE>
	int getTickValue(const std::vector<_TYPE>& v, int bufferCount, _TYPE* pSmall, _TYPE* pBig)
	{
		if (v.size() < bufferCount * 2) return -1;

		//direction=0时弹出最小值，否则弹出最大值
		auto fnUpdateVector = [](_TYPE value, std::vector<_TYPE>& vBuffer, int bufferSize, int direction)
		{
			bool hasAdded = false;;
			for (auto iter = vBuffer.begin(); iter != vBuffer.end(); ++iter)
			{
				if (value <= *iter)
				{
					vBuffer.insert(iter, value);
					hasAdded = true;
					break;
				}
			}
			if (!hasAdded) vBuffer.push_back(value);

			if (vBuffer.size() > bufferSize) {
				if (direction == 0) vBuffer.erase(vBuffer.begin());
				else vBuffer.pop_back();
			}
		};

		std::vector<_TYPE> vBigBuffer;
		std::vector<_TYPE> vSmallBuffer;
		for (auto d : v) {
			fnUpdateVector(d, vBigBuffer, bufferCount, 0);
			fnUpdateVector(d, vSmallBuffer, bufferCount, 1);
		}

		if (pSmall != nullptr)*pSmall = vSmallBuffer.back();
		if (pBig != nullptr)*pBig = vBigBuffer.front();
		return 0;
	}
	
	/**
	 * @desc:计算刻度值
	 * @author:王杰 2023/1/30
	 * @params:
	 *	v-输入数据集；
	 *	cursorRate-刻度比率；
	 *	pSmall-低刻度值；
	 *	pBig-高刻度值
	 * @ret int。0-成功 1-失败
	 */
	template<typename _TYPE>
	int getTickValue(const std::vector<_TYPE>& v, double cursorRate, _TYPE* pSmall, _TYPE* pBig)
	{
		int bufferCount = v.size()*cursorRate;
		return getTickValue(v, bufferCount, pSmall, pBig);
	}

	/**
	 * @desc:获取容量最大的元素
	 * @author:王杰 2023/06/08
	 * @params:
	 *	v-输入数据集；
	 * @ret _TYPE。容量最大的元素
	 */
	template<typename _TYPE>
	_TYPE getLargetElement(const std::vector<_TYPE>& v) {
		uint maxSize = 0;
		_TYPE d;
		for (auto e : v) {
			if (e.size() > maxSize) {
				maxSize = e.size();
				d = e;
			}
		}
		return d;
	}

};
